/**
 * @description: 严格类型判断
 * @param {any} typeObject
 * @return {String} Object Array
 */
function toType(typeObject) {
  return Object.prototype.toString
    .call(typeObject)
    .split(' ')[1]
    .replace(']', '')
}

/**
 * @description: 严格类型判断
 * @param {any} typeObject
 * @param {String} type
 * @return {Boolean}
 */
function isType(typeObject, type) {
  const targetType = toType(typeObject)
  return targetType === type
}

/**
 * @description: 查找key是否在对象上（不包括对象原型）
 * @param {Object} obj
 * @param {String} key
 * @return {Boolean}
 */
function hasOwn(obj, key) {
  if (obj) {
    return Object.hasOwnProperty.call(obj, key)
  } else {
    throw Error('the obj params is required')
  }
}

/**
 * @description: 字符串去除空格
 * @param {String} str
 * @param {String} insetAuto 是否去除字符串内部空白符
 * @return {String}
 */
function trimAll(str, insetAuto) {
  if (str) {
    if (!insetAuto) {
      return str.trim()
    } else {
      return str.replace(/\s/gm, '')
    }
  } else {
    return str
  }
}

/**
 * This is just a simple version of deep copy
 * Has a lot of edge cases bug
 * If you want to use a perfect deep copy, use lodash's _.cloneDeep
 * @param {Object} source
 * @returns {Object}
 */
function deepClone(source) {
  if (!source && typeof source !== 'object') {
    throw Error('error arguments', 'deepClone')
  }
  const targetObj = source.constructor === Array ? [] : {}
  Object.keys(source).forEach((keys) => {
    if (source[keys] && typeof source[keys] === 'object') {
      targetObj[keys] = deepClone(source[keys])
    } else {
      targetObj[keys] = source[keys]
    }
  })
  return targetObj
}

/**
 * @description: 深拷贝
 * @param {Object} jsonObject
 * @return {Object}
 */

function extend(jsonObject) {
  return JSON.parse(JSON.stringify(jsonObject))
}

/**
 * @description: 混入
 * @param {Object} to
 * @param {Object} from
 * @return {Object}
 */
export function mixin(to, from) {
  if (!from) { return to }
  let key, toVal, fromVal
  const keys = Object.keys(from)
  for (let i = 0, len = keys.length; i < len; i++) {
    key = keys[i]
    // in case the object is already observed...
    if (key === '__ob__') { continue }
    toVal = to[key] // child
    fromVal = from[key] // parent
    const toValType = toType(toVal)
    const fromValType = toType(fromVal)
    if (!hasOwn(to, key)) {
      to[key] = fromVal // 若to没有此key，添加它
    } else if (
      (toValType === 'Object' || toValType === 'Array') &&
      toVal !== fromVal &&
      toValType === fromValType
    ) {
      // 若to有此key，且不等
      // 若to有此key，值非对象，否则进行深度合并
      mixin(toVal, fromVal)
    }
  }
  return to
}

/**
 * @description: 合并
 * @param {Object} to
 * @param {Object} from
 * @return {Object}
 */
export function merge(to, from) {
  if (!from) { return to }
  let key, toVal, fromVal
  const keys = Object.keys(from)
  for (let i = 0, len = keys.length; i < len; i++) {
    key = keys[i]
    // in case the object is already observed...
    if (key === '__ob__') { continue }
    toVal = to[key] // child
    fromVal = from[key] // parent
    const toValType = toType(toVal)
    const fromValType = toType(fromVal)
    if (
      (toValType === 'Object' || toValType === 'Array') &&
      toValType === fromValType &&
      toVal !== fromVal
    ) {
      // 若to有此key，且不等
      // 若to有此key，值非对象，否则进行深度合并
      merge(toVal, fromVal)
    } else {
      to[key] = fromVal
    }
  }
  return to
}

module.exports = {
  toType,
  isType,
  hasOwn,
  trimAll,
  mixin,
  merge,
  deepClone,
  extend
}
